1. Spring的资源抽象接口
假如有一个文件位于Web应用的类路径下,用户可以通过以下方式对这个文件资源进行访问:
- 通过
FileSystemResource
以文件系统绝对路径的方式进行访问; - 通过
ClassPathResource
以类路径的方式进行访问; - 通过
ServletContextResource
以相对于Web应用根目录的方式进行访问。
2. BeanFactory的类体系结构
BeanFactory
:位于类结构树的顶端,最主要的方法是getBean(String beanName)
,从容器中返回特定类型的beanListableBeanFactory
:该接口定义了访问容器中Bean基本信息的若干方法HierarchicalBeanFactory
:父子级联IoC容器的接口,子容器可以通过接口方法访问父容器ConfigurableBeanFactory
:增强了IoC容器的可定制性AutowireCapableBeanFactory
:定义了将容器中的bean按照某种规则进行自动装配的方法SingletonBeanRegistry
:定义了允许在运行期向容器注册单实例bean的方法BeanDefinitionRegistry
:每一个bean在容器中通过BeanDefinition
对象表示,BeanDefinitionRegistry
定义了向容器手工注册bean的方法- Spring在
DefaultSingletonBeanRegistry
类中提供了一个用于缓存单实例bean的缓存器,以HashMap
实现,单实例的bean以beanName
为key保存在这个HashMap
中
3. ApplicationContext的类体系结构
ApplicationEventPublisher
:让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。实现了ApplicationListener
事件监听接口的Bean 可以接收到容器事件,并对事件进行响应处理。在ApplicationContext
抽象实现类AbstractApplicationContext
中,我们可以发现存在一个ApplicationEventMulticaster
,它负责保存所有监听器,以便在容器产生上下文事件时通知这些事件监听者。MessageSource
:为应用提供i18n国际化消息访问的功能;ResourcePatternResolver
:所有ApplicationContext
实现类都实现了类似于PathMatchingResourcePatternResolver
的功能,可以通过带前缀的Ant风格的资源文件路径装载Spring的配置文件。LifeCycle
:该接口是Spring 2.0加入的,该接口提供了start()
和stop()
两个方法,主要用于控制异步处理过程。在具体使用时,该接口同时被ApplicationContext
实现及具体Bean实现,ApplicationContext
会将start/stop
的信息传递给容器中所有实现了该接口的Bean,以达到管理和控制JMX、任务调度等目的。ConfigurableApplicationContext
扩展于ApplicationContext
,它新增加了两个主要的方法:refresh()
和close()
,让ApplicationContext
具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用refresh()
即可启动应用上下文,在已经启动的状态下,调用refresh()
则清除缓存并重新装载配置信息,而调用close()
则可关闭应用上下文。
4. WebApplicantContext体系结构
- 它允许从相对于Web根目录的路径中加载配置文件完成初始化工作。从
WebApplicationContext
中可以获取ServletContext
引用,整个Web应用上下文对象将作为属性放置在ServletContext
中,以便Web应用环境可以访问spring上下文。 WebApplicationContext
扩展了ApplicationContext
,WebApplicationContext
定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
,在上下文启动时,我们可以直接通过下面的语句从web容器中获取WebApplicationContext
:
1 | WebApplicationContext wac=(WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); |
5. BeanFactory中Bean的生命周期
5.1 Bean生命周期
- 如果容器注册
InstantiationAwareBeanPostProcessor
接口,调用postProcessBeforeInstantiation
方法 - Bean的实例化(调用默认构造器)
- 如果容器注册
InstantiationAwareBeanPostProcessor
接口,调用postProcessAfterInstantiation
方法 - 如果容器注册
InstantiationAwareBeanPostProcessor
接口,调用postProcessPropertyValues
方法 - 根据配置设置属性值
- 如果Bean实现了
BeanNameAware
接口,调用BeanNameAware
接口的setBeanName
方法 - 如果Bean实现了
BeanFactoryAware
接口,调用BeanFactoryAware
接口的setBeanFactory
方法 - 如果容器注册了
BeanPostProcessor
接口,调用BeanPostProcessor
接口的postProcessBeforeInitialization
方法 - 如果Bean实现了
InitializingBean
接口,调用InitializingBean
接口的afterPropertiesSet
方法 - 通过
init-method
属性配置的初始方法 - 如果容器注册了
BeanPostProcessor
接口,调用BeanPostProcessor
接口的postProcessAfterInitialization
方法 - 如果是单例模式,将Bean放入缓存池中;容器销毁时,调用
DisposableBean的destroy
方法;最后调用destroy-method
方法 - 如果是多例模式,将Bean交给调用者。
5.2 初始化过程中的方法分类
- bean自身的方法:如调用bean构造函数实例化bean,调用
Setter
设置bean的属性值,以及通过<bean>
的init-method
和destory-method
所指定的方法; - bean级生命周期接口方法:如
BeanNameAware
、BeanFactoryAware
、InitializingBean
和DisposableBean
,这些接口方法由bean类直接实现; - 容器级生命周期接口方法:如
InstantiationAwareBeanPostProcessor
和BeanPostProcessor
这两个接口实现,一般称它们的实现类为“后处理器”。
5.3 说明
- Spring的AOP等功能即通过
BeanPostProcessor
实现 - 如果
<bean>
通过init-method
属性定义了初始化方法,将执行这个方法 - 如果bean的作用范围为
scope="prototype"
,将bean返回给调用者之后,调用者负责bean的后续生命的管理,Spring不再管理这个bean的生命周期;如果scope="singleton"
,则将bean放入到Spring IoC容器的缓存池中,并将bean的引用返回给调用者,Spring继续管理这些bean的后续生命周期 - 对于单例的bean,当容器关闭时,将触发Spring对bean的后续生命周期的管理工作。如果bean实现了
DisposableBean
接口,则将调用接口的destroy()
方法 - 对于单例的bean,如果通过
destroy-method
指定了bean的销毁方法,Spring将执行这个方法 - 后处理器的实际调用顺序和注册顺序无关,在具有多个后处理器的情况下,必须通过实现
org.springframework.core.Ordered
接口确定调用顺序
5.4 测试
applicationContext.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
Car
1 | package com.data; |
MyBeanPostProcessor
1 | package com.beanfactory; |
TestBeanFactory
1 | package config; |
- 结果
1 | 二月 09, 2017 10:58:59 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions |
6. ApplicationContext中的Bean生命周期
6.1 流程图
6.2 说明
- 如果bean实现了
org.springframework.context.ApplicationContextAware
接口,会增加一个调用该接口方法setApplicationContext()
的步骤 - 如果配置文件中声明了工厂后处理器接口
BeanFactoryPostProcessor
的实现类,则应用上下文在加载配置文件之后、初始化bean实例之前将调用这些BeanFactoryPostProcessor
对配置信息进行加工处理 ApplicationContext
和BeanFactory
的不同之处在于:前者会利用Java反射机制自动识别出配置文件中定义的BeanPostProcessor
、InstantiationAwareBeanPostProcessor
和BeanFactoryPostProcessor
,并自动将它们注册到应用上下文中;而后者需要在代码中通过手工调用addBeanPostProcessor()
方法进行注册- 对bean的初始化,
BeanFactory
发生在第一次调用bean时,而ApplicationContext
发生在初始化容器时
6.3 测试
MyBeanPostProcessor
同上Car
增加对ApplicationContextAware
接口的实现,并添加@PostConstruct
和@PreDestroy
的注解方法
1 | package com.data; |
MyBeanFactoryPostProcessor
1 | package com.beanfactory; |
- 基于Java类的Spring配置:
AnnotationBeans
1 | package config; |
TestApplicationContext
1 | package config; |
- 结果
1 | 二月 09, 2017 11:55:25 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh |
7. 容器内部工作机制
7.1 启动源码
Spring的AbstractApplicationContext的refresh()
方法定义了Spring容器在加载配置文件后的各项处理工作
1 |
|
7.2 容器启动流程
ContextLoaderListener
通过调用继承自ContextLoader
的initWebApplicationContext
方法实例化SpringIoC容器。在实例化Spring IoC容器的过程中,最主要的两个方法是createWebApplicationContext
和configureAndRefreshWebApplicationContext方
法。createWebApplicationContext
方法用于返回XmlWebApplicationContext
实例,即Web环境下的SpringIoC容器。configureAndRefreshWebApplicationContext
用于配XmlWebApplicationContext
,读取web.xml
中通过contextConfigLocation
标签指定的XML文件,通过调用refresh
来调用AbstractApplicationContext
中的refresh
初始化。
BeanFactory
实例化XML文件中配置的bean,Spring将配置文件的bean的信息解析成为一个个的BeanDefinition
对象并装入到容器的Bean定义注册表,但此时Bean还未初始化;obtainFreshBeanFactory()
会调用自身的refreshBeanFactory()
,而refreshBeanFactory()
方法由子类AbstractRefreshableApplicationContext
实现,该方法返回了一个创建的DefaultListableBeanFactory
对象,这个对象就是由ApplicationContext
管理的BeanFactory
容器对象;- 调用工厂后处理器:根据反射机制从
BeanDefinitionRegistry
中找出所有BeanFactoryPostProcessor
类型的Bean,并调用其postProcessBeanFactory()
接口方法。经过第一步加载配置文件,已经把配置文件中定义的所有bean装载到BeanDefinitionRegistry
这个Beanfactory
中,对于ApplicationContext
应用来说这个BeanDefinitionRegistry
类型的BeanFactory
就是Spring默认的DefaultListableBeanFactory
- 注册Bean后处理器:根据反射机制从
BeanDefinitionRegistry
中找出所有BeanPostProcessor
类型的Bean,并将它们注册到容器Bean后处理器的注册表中; - 初始化消息源:初始化容器的国际化信息资源;
- 初始化应用上下文事件广播器;
- 初始化其他特殊的Bean;
- 注册事件监听器;
- 初始化singleton的Bean:实例化所有singleton的Bean,并将它们放入Spring容器的缓存中;
- 发布上下文刷新事件:在此处时容器已经启动完成,发布容器
refresh
事件创建上下文刷新事件,事件广播器负责将些事件广播到每个注册的事件监听器中。
7.3 Bean加载流程
ResourceLoader
从存储介质中加载Spring配置文件,并使用Resource
表示这个配置文件的资源;BeanDefinitionReader
读取Resource
所指向的配置文件资源,然后解析配置文件。配置文件中每一个<bean>
解析成一个BeanDefinition
对象,并保存到BeanDefinitionRegistry
中;- 容器扫描
BeanDefinitionRegistry
中的BeanDefinition
,使用Java的反射机制自动识别出Bean工厂后处理器(实现BeanFactoryPostProcessor
接口)的Bean,然后调用这些Bean工厂后处理器对BeanDefinitionRegistry
中的BeanDefinition
进行加工处理。主要完成以下两项工作:- 对使用到占位符的
<bean>
元素标签进行解析,得到最终的配置值,这意味对一些半成品式的BeanDefinition
对象进行加工处理并得到成品的BeanDefinition
对象; - 对
BeanDefinitionRegistry
中的BeanDefinition
进行扫描,通过Java反射机制找出所有属性编辑器的Bean(实现java.beans.PropertyEditor
接口的Bean),并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry
);
- 对使用到占位符的
- Spring容器从
BeanDefinitionRegistry
中取出加工后的BeanDefinition
,并调用InstantiationStrategy
着手进行Bean实例化的工作; - 在实例化Bean时,Spring容器使用
BeanWrapper
对Bean进行封装,BeanWrapper
提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefinition
以及容器中属性编辑器,完成Bean属性的设置工作; - 利用容器中注册的Bean后处理器(实现
BeanPostProcessor
接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean。
8. Spring事件
Spring事件体系包括三个组件:事件,事件监听器,事件广播器。
- 事件:
ApplicationEvent
- 事件监听器:
ApplicationListener
,对监听到的事件进行处理。 - 事件广播器:
ApplicationEventMulticaster
,将Spring publish的事件广播给所有的监听器。Spring在ApplicationContext
接口的抽象实现类AbstractApplicationContext
中完成了事件体系的搭建。 AbstractApplicationContext
拥有一个applicationEventMulticaster
成员变量,applicationEventMulticaster
提供了容器监听器的注册表。
8.1 事件广播器的初始化
1 | private void initApplicationEventMulticaster() throws BeansException { |
用户可以在配置文件中为容器定义一个自定义的事件广播器,只要实现ApplicationEventMulticaster
就可以了,Spring会通过反射的机制将其注册成容器的事件广播器,如果没有找到配置的外部事件广播器,Spring自动使用 SimpleApplicationEventMulticaster
作为事件广播器。
8.2 注册事件监听器
1 | private void registerListeners () throws BeansException { |
Spring根据反射机制,使用ListableBeanFactory
的getBeansOfType
方法,从BeanDefinitionRegistry
中找出所有实现 org.springframework.context.ApplicationListener
的Bean,将它们注册为容器的事件监听器,实际的操作就是将其添加到事件广播器所提供的监听器注册表中。
8.3 发布事件
1 | public void publishEvent(ApplicationEvent event) { |
在AbstractApplicationContext
的publishEvent
方法中, Spring委托ApplicationEventMulticaster
将事件通知给所有的事件监听器
8.4 Spring默认的事件广播器SimpleApplicationEventMulticaster
1 | public void multicastEvent( final ApplicationEvent event) { |
遍历注册的每个监听器,并启动来调用每个监听器的onApplicationEvent
方法。
由于SimpleApplicationEventMulticaster
的taskExecutor
的实现类是SyncTaskExecutor
,因此,事件监听器对事件的处理,是同步进行的。
8.5 举例
springEvent.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
MockEvent
1 | package com.event; |
MockEventListener
1 | package com.event; |
MockEventPublisher
1 | package com.event; |
MockEventTest
1 | package com.event; |
- 结果
1 | 二月 09, 2017 9:57:43 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh |